package com.liuqh.tag.config.shiro;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.apache.commons.lang3.StringUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * token过滤器，主要目的是为了解决cookie跨域不可以用的问题 1.登录成功，把token(sessionId)，添加到header返回给前端
 * 2.请求头header里有token，就手动添加把这个token添加到cookie
 *
 * @author liuqinghua
 * @date 2023-7-14
 */
//@Configuration
@Slf4j
//@@WebFilter(urlPatterns = "/*")表示要拦截的请求，/*表示拦截所有请求
//@WebFilter(urlPatterns = "/*")
public class TokenFilter implements Filter {
	private final String shiroCookieName = "shiro.session.id";

	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
			throws IOException, ServletException {
		log.info("TokenFilter.doFilter...");
		// 将形参servletRequest强制转换为HttpServletRequest类型，以便获取请求的URL地址和请求头
		HttpServletRequest request = (HttpServletRequest) servletRequest;
		ModifyHttpServletRequestWrapper requestWrapper = new ModifyHttpServletRequestWrapper(request);
		String token = request.getHeader("authorization");
		Enumeration<String> cookies = requestWrapper.getHeaders("cookie");
		boolean hasShiroSessionId = false;
		while (cookies.hasMoreElements()) {
			String cookie = cookies.nextElement();
			if (cookie.startsWith(shiroCookieName)) {
				hasShiroSessionId = true;
				break;
			}
		}
		if (hasShiroSessionId) {
			// 如果本来就有cookie本来就有shiro的sessionId
			log.info("有cookie");
		} else if (StringUtils.isNotBlank(token)) {
			// 手动添加cookie
			requestWrapper.putCookie(shiroCookieName, token);
			requestWrapper.addHeader("cookie", shiroCookieName + "=" + token);
			log.info("手动添加shiro cookie:{}", token);
		} else {
			log.info("无cookie");
		}
		filterChain.doFilter(requestWrapper, servletResponse);

	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		log.info("TokenFilter init...");
	}

	@Override
	public void destroy() {
		log.info("TokenFilter destroy...");
	}

	/**
	 * 修改cookie信息
	 */
	private class ModifyHttpServletRequestWrapper extends HttpServletRequestWrapper {
		private Map<String, String> mapCookies;
		private final Map<String, String> headers;

		ModifyHttpServletRequestWrapper(HttpServletRequest request) {
			super(request);
			this.mapCookies = new HashMap<>();
			this.headers = new HashMap<String, String>();
		}

		void putCookie(String name, String value) {
			this.mapCookies.put(name, value);
		}

		public void addHeader(String key, String value) {
			headers.put(key, value);
		}

		public Cookie[] getCookies() {
			HttpServletRequest request = (HttpServletRequest) getRequest();
			Cookie[] cookies = request.getCookies();
			if (mapCookies == null || mapCookies.isEmpty()) {
				return cookies;
			}
			if (cookies == null || cookies.length == 0) {
				List<Cookie> cookieList = new LinkedList<>();
				for (Map.Entry<String, String> entry : mapCookies.entrySet()) {
					String key = entry.getKey();
					if (key != null && !"".equals(key)) {
						cookieList.add(new Cookie(key, entry.getValue()));
					}
				}
				if (cookieList.isEmpty()) {
					return cookies;
				}
				return cookieList.toArray(new Cookie[cookieList.size()]);
			} else {
				List<Cookie> cookieList = new ArrayList<>(Arrays.asList(cookies));
				for (Map.Entry<String, String> entry : mapCookies.entrySet()) {
					String key = entry.getKey();
					if (key != null && !"".equals(key)) {
						for (int i = 0; i < cookieList.size(); i++) {
							if (cookieList.get(i).getName().equals(key)) {
								cookieList.remove(i);
							}
						}
						cookieList.add(new Cookie(key, entry.getValue()));
					}
				}
				return cookieList.toArray(new Cookie[cookieList.size()]);
			}
		}

		/**
		 * 获得value
		 *
		 * @param key
		 * @return
		 */
		@Override
		public String getHeader(String key) {
			String value = super.getHeader(key);
			if (value == null) {
				value = headers.get(key);
			}
			return value;
		}

		/**
		 * 获得value集合
		 *
		 * @param key
		 * @return
		 */
		@Override
		public Enumeration<String> getHeaders(String key) {
			Enumeration<String> enumeration = super.getHeaders(key);
			List<String> valueList = Collections.list(enumeration);
			if (headers.containsKey(key)) {
				valueList.add(headers.get(key));
			}
			return Collections.enumeration(valueList);
		}

		/**
		 * 获得key集合
		 *
		 * @return
		 */
		@Override
		public Enumeration<String> getHeaderNames() {
			List<String> keyList = Collections.list(super.getHeaderNames());
			keyList.addAll(headers.keySet());
			return Collections.enumeration(keyList);
		}
	}
}
